#!/bin/bash

# TODO LIST
# 1.在低版本安装rpm时使用低版本yum源避免升级大量依赖包（对于euleros系统用户需要-v 指定euleros版本）


os_version=""
os_type=""
deploy_work_dir=$(realpath $(dirname $0))

DOCKER_HUB='hub.oepkgs.net'
DOCKER_HUB_TAG_PREFIX="${DOCKER_HUB}/a-ops"
DOCKER_HTTPS_PROXY='http://user:pass@proxy.com:8080'


LTS_2203_EPOL='http://121.36.84.172/dailybuild/openEuler-22.03-LTS/openEuler-22.03-LTS/EPOL/main/'$(uname -m)
LTS_2203_EPOL_UPDATE='http://mirrors.aliyun.com/openeuler/openEuler-22.03-LTS/EPOL/update/main/'$(uname -m)
LTS_2203_EVERYTHING='http://mirrors.aliyun.com/openeuler/openEuler-22.03-LTS/everything/'$(uname -m)
LTS_2203_UPDATE='http://mirrors.aliyun.com/openeuler/openEuler-22.03-LTS/update/'$(uname -m)

LTS_2203_SP1_EPOL='http://mirrors.aliyun.com/openeuler/openEuler-22.03-LTS-SP1/EPOL/main/'$(uname -m)
LTS_2203_SP1_EPOL_UPDATE='http://mirrors.aliyun.com/openeuler/openEuler-22.03-LTS-SP1/EPOL/update/main/'$(uname -m)
LTS_2203_SP1_EVERYTHING='http://mirrors.aliyun.com/openeuler/openEuler-22.03-LTS-SP1/everything/'$(uname -m)
LTS_2203_SP1_UPDATE='http://mirrors.aliyun.com/openeuler/openEuler-22.03-LTS-SP1/update/'$(uname -m)

LTS_2003_SP1_EPOL='http://repo.openeuler.org/openEuler-20.03-LTS-SP1/EPOL/'$(uname -m)
LTS_2003_SP1_EPOL_UPDATE='http://repo.openeuler.org/openEuler-20.03-LTS-SP1/EPOL/update/'$(uname -m)
LTS_2003_SP1_EVERYTHING='http://repo.openeuler.org/openEuler-20.03-LTS-SP1/everything/'$(uname -m)
LTS_2003_SP1_UPDATE='http://repo.openeuler.org/openEuler-20.03-LTS-SP1/update/'$(uname -m)

EPOL_REPO_URL=""
EPOL_UPDATE_REPO_URL=""
EVERYTHING_REPO_URL=""
UPDATE_REPO_URL=""
DOCKER_TAG=""
DOCKER_USE_PROXY=""
UPDATE_GALA=""
GALA_DEPLOY_MODE="rpm"
COMPONENT=""

GOPHER_LOCAL_RPM=""
LIBBPF_LOCAL_RPM="$(ls repo/libbpf-*$(uname -m).rpm 2>/dev/null)"
FLAMEGRAPH_LOCAL_RPM="$(ls repo/flamegraph-*.rpm 2>/dev/null)"

KAFKA_PORT=9092
PROMETHEUS_PORT=9090
ES_PORT=9200
ARANGODB_PORT=8529
PYROSCOPE_PORT=4040

KAFKA_ADDR="localhost:${KAFKA_PORT}"
PROMETHEUS_ADDR="localhost:${PROMETHEUS_PORT}"
ES_ADDR="localhost:${ES_PORT}"
ARANGODB_ADDR="localhost:${ARANGODB_PORT}"
PYROSCOPE_ADDR="localhost:${PYROSCOPE_PORT}"

PROMETHEUS_SCRAPE_LIST=""

#=======Common Utils========#
function echo_err_exit() {
    echo -e "\e[31m $@ \e[0m"
    exit 1;
}

function echo_info() {
    echo -e "\e[32m $@ \e[0m"
}

function echo_warn() {
    echo -e "\e[33m $@ \e[0m"
}

function print_usage() {
    echo "usage : sh deploy.sh [COMPONENT] [OPTION]"

    echo "supported COMPONENT:"
    echo "      gopher|ops|middleware|opengauss|grafana"
    echo ""
    echo "gopher options:"
    echo "      [-K|--kafka <kafka_server>] [-p|--pyroscope <pyroscope_server>] [--docker]"
    echo "      [-t|--tag <gopher_image_tag>] [--proxy] [-U|--update]"
    echo ""
    echo "ops options:"
    echo "      [-K|--kafka <kafka_server>] [-P|--prometheus <prometheus_server>] [-A|--arangodb <arangodb_server>]"
    echo "      [-U|--update] [--docker] [--proxy]"
    echo ""
    echo "opengauss options:"
    echo "      [-D|--datadir <opengauss data dir>] [--proxy]"
    echo ""
    echo "middleware options:"
    echo "      [-K|--kafka <kafka_server>] [-P <prometheus_addr1[,prometheus_addr2,prometheus_addr3,...]>]"
    echo "      [-E|--elastic <es_server>] [-A|--arangodb]"
    echo ""
    echo "grafana options:"
    echo "      [-P|--prometheus <prometheus_server>] [-p|--pyroscope <pyroscope_server>]"
    echo "      [-E|--elastic <es_server>] [--proxy]"
    echo ""
    echo "Common options:"
    echo "      --docker         Deploy components with docker images, only support gopher"
    echo "      -U,--update      Update rpms when they are already installed, only works in rpm mode"
    echo "      --proxy          Configure docker proxy before pull images (Recommended for intranet users)"
    echo "      -t,--tag         gopher docker image tag to pull, supported tags: euleros-v2r9, 20.03-lts, 20.03-lts-sp1, 22.03-lts, 22.03-lts-sp1"
    echo ""
}

function install_rpm() {
    rpm="$1"
    if [ ! -n "$rpm" ] ; then
        exit 1
    fi

    if [ "x${UPDATE_GALA}" == "x" ] && rpm -q "$rpm" >/dev/null 2>&1; then
        echo "$rpm is already installed, skip..."
        return
    fi

    yum install -y $rpm  \
        --repofrompath="epol_deploy,$EPOL_REPO_URL" \
        --repofrompath="epol_update_deploy,$EPOL_UPDATE_REPO_URL" \
        --repofrompath="everything_deploy,$EVERYTHING_REPO_URL" \
        --repofrompath="update_deploy,$UPDATE_REPO_URL" --nogpgcheck
    [ $? -ne 0 ] && echo_err_exit "Error: failed to install $rpm, please check repo!"
}

function install_local_rpm() {
    rpm="$1"
    if [ ! -n "$rpm" ] || [ ! -f "$rpm" ] ; then
        exit 1
    fi

    yum install -y $rpm  \
        --repofrompath="epol_deploy,$EPOL_REPO_URL" \
        --repofrompath="epol_update_deploy,$EPOL_UPDATE_REPO_URL" \
        --repofrompath="everything_deploy,$EVERYTHING_REPO_URL" \
        --repofrompath="update_deploy,$UPDATE_REPO_URL" --nogpgcheck
    [ $? -ne 0 ] && echo_err_exit "Error: failed to install $rpm, please check repo!"
}

function config_docker_proxy() {
    mkdir -p /etc/systemd/system/docker.service.d
    cat > /etc/systemd/system/docker.service.d/deploy.conf << EOF
[Service]
Environment="HTTPS_PROXY=${DOCKER_HTTPS_PROXY}"
EOF

    if  ! grep "^INSECURE_REGISTRY" /etc/sysconfig/docker | grep -q "${DOCKER_HUB}" ; then
        cat >> /etc/sysconfig/docker << EOF
INSECURE_REGISTRY='--insecure-registry ${DOCKER_HUB}'
EOF
    fi
    systemctl daemon-reload
    systemctl restart docker || echo_err_exit "Error: fail to configure docker proxy"
}

function docker_pull_image() {
    tag_name="$1"
    if [ ! -n "$tag_name" ] ; then
        exit 1
    fi

    docker --version >/dev/null 2>&1  || echo_err_exit "Error: Docker cmd not found, please install docker firstly"
    if [ "x${DOCKER_USE_PROXY}" == "xyes" ] ; then
        echo "Configuring docker proxy for intranet users, please fill \"DOCKER_HTTPS_PROXY\" with your proxy info"
        config_docker_proxy
    fi
    docker pull ${DOCKER_HUB_TAG_PREFIX}/"${tag_name}"
    [ $? -ne 0 ] && echo_err_exit "Error: failed to pull docker image:" $tag_name
}

function get_port_from_addr() {
    addr=$1
    port=""

    if echo $addr | grep -q ":" ; then
        port=${addr##*:}
        if [ -z "${port}" ] || ! echo $port | grep -q '^[[:digit:]]*$' ; then
            echo_err_exit "Invalid port specified: $addr"
        fi
    fi
    echo $port
}

function get_ip_from_addr() {
    addr=$1
    echo ${addr%:*}
}

function addr_add_port() {
    addr="${1}"
    default_port="${2}"

    if [ -z "${addr}" ] || [ -z "${default_port}" ] ; then
        echo_err_exit "Invalid parameter in addr_add_port()"
    fi

    port=$(get_port_from_addr $addr)
    if [ -z "${port}" ] ; then
        echo "${addr}:${default_port}"
    else
        echo "${addr}"
    fi
}

function check_osversion_decide_repo() {
    os_version=$(cat /etc/openEuler-release 2> /dev/null)

    if [ -z "$os_version" ] ; then
        os_version=$(cat /etc/euleros-release 2> /dev/null)
        [ -z "$os_version" ] && echo_err_exit "Unsupport OS type, aborting"

        echo_info "Deploying on $os_version"
        os_type="euleros"
        if echo "$os_version" | grep -q '(SP9' ; then
            EPOL_REPO_URL="${LTS_2003_SP1_EPOL}"
            EPOL_UPDATE_REPO_URL="${LTS_2003_SP1_EPOL_UPDATE}"
            EVERYTHING_REPO_URL="${LTS_2003_SP1_EVERYTHING}"
            UPDATE_REPO_URL="${LTS_2003_SP1_UPDATE}"
            GOPHER_LOCAL_RPM="$(ls repo/gala-gopher*v2r9.$(uname -m)* 2>/dev/null)"
            os_version="other"
        elif echo "$os_version" | grep -q '(SP10' ; then
            EPOL_REPO_URL="${LTS_2003_SP1_EPOL}"
            EPOL_UPDATE_REPO_URL="${LTS_2003_SP1_EPOL_UPDATE}"
            EVERYTHING_REPO_URL="${LTS_2003_SP1_EVERYTHING}"
            UPDATE_REPO_URL="${LTS_2003_SP1_UPDATE}"
            os_version="other"
            GOPHER_LOCAL_RPM="$(ls repo/gala-gopher*.oe1$(uname -m)* 2>/dev/null)"
        elif echo "$os_version" | grep -q '(SP11' ; then
            EPOL_REPO_URL="${LTS_2203_EPOL}"
            EPOL_UPDATE_REPO_URL="${LTS_2203_EPOL_UPDATE}"
            EVERYTHING_REPO_URL="${LTS_2203_EVERYTHING}"
            UPDATE_REPO_URL="${LTS_2203_UPDATE}"
        else
            echo_err_exit "Unsupport OS type, aborting"
        fi
        return
    fi

    os_type="openEuler"
    echo_info "Deploying on $os_version"
    # openEuler 2203
    if echo "$os_version" | grep -q '22.03' ; then
        if echo "$os_version" | grep -q 'SP1' ; then
            EPOL_REPO_URL="${LTS_2203_SP1_EPOL}"
            EPOL_UPDATE_REPO_URL="${LTS_2203_SP1_EPOL_UPDATE}"
            EVERYTHING_REPO_URL="${LTS_2203_SP1_EVERYTHING}"
            UPDATE_REPO_URL="${LTS_2203_SP1_UPDATE}"
        else
            EPOL_REPO_URL="${LTS_2203_EPOL}"
            EPOL_UPDATE_REPO_URL="${LTS_2203_EPOL_UPDATE}"
            EVERYTHING_REPO_URL="${LTS_2203_EVERYTHING}"
            UPDATE_REPO_URL="${LTS_2203_UPDATE}"
        fi
        return
    fi

    os_version="other"
    EPOL_REPO_URL="${LTS_2003_SP1_EPOL}"
    EPOL_UPDATE_REPO_URL="${LTS_2003_SP1_EPOL_UPDATE}"
    EVERYTHING_REPO_URL="${LTS_2003_SP1_EVERYTHING}"
    UPDATE_REPO_URL="${LTS_2003_SP1_UPDATE}"
    GOPHER_LOCAL_RPM="$(ls repo/gala-gopher*.oe1$(uname -m)* 2>/dev/null)"
}

#=======openGauss Server Deployment=======#
OPNEGAUSS_DEPLOY_SCRIPT='./opengauss/create_master_slave.sh'
GS_DATADIR=""
function parse_arg_opengauss_server() {
    ARGS=`getopt -a -o D: --long proxy,datadir: -- "$@"`
    [ $? -ne 0 ] && echo_err_exit "parse arg error, terminating..."
    eval set -- "${ARGS}"
    while true
    do
        case $1 in
            --proxy)
                DOCKER_USE_PROXY="yes";;
            -D|--datadir)
                GS_DATADIR="${2}"
                shift;;
            --)
                shift
                break;;
            *)
                echo_err_exit "getopt param error";;
        esac
        shift
    done
}

function deploy_opengauss_server() {
    echo_info "======Deploying openGauss Server======"
    if [ -n "${GS_DATADIR}" ] && [ ! -d "${GS_DATADIR}" ] ; then
        echo_err_exit "Invalid openGauss data dir"
    fi

    echo -e "[1] Pulling opengauss docker image"
    docker_pull_image "opengauss:3.0.0"

    echo -e "\n[2] Creating opengauss master and slave container"
    if [ -f "${OPNEGAUSS_DEPLOY_SCRIPT}" ] ; then
        GS_DATADIR="$GS_DATADIR" sh ${OPNEGAUSS_DEPLOY_SCRIPT}
        [ $? -ne 0 ] && exit 1
    else
        echo "Error: opengauss script create_master_slave.sh not found"
        exit 1
    fi

    echo -e "\n[4] Creating opengauss database and user"
    systemctl restart docker   # prevent iptables-related issues
    container_id=$(docker ps | grep -w opengauss_master | awk '{print $1}')
    docker exec -it ${container_id} /bin/bash -c  "su - omm -c \"echo create database tpccdb\; > ~/tmp.gsql\""
    docker exec -it ${container_id} /bin/bash -c  "su - omm -c \"echo create user tpcc with password \'tpcc_123456\'\; >> ~/tmp.gsql\""
    docker exec -it ${container_id} /bin/bash -c  "su - omm -c \"echo grant all privilege to tpcc\; >> ~/tmp.gsql\""
    docker exec -it ${container_id} /bin/bash -c  "su - omm -c \"echo create user opengauss_exporter with monadmin password \'opengauss_exporter123\'\; >> ~/tmp.gsql\""
    docker exec -it ${container_id} /bin/bash -c  "su - omm -c \"echo grant usage on schema dbe_perf to opengauss_exporter\; >> ~/tmp.gsql\""
    docker exec -it ${container_id} /bin/bash -c  "su - omm -c \"echo grant select on pg_stat_replication to opengauss_exporter\; >> ~/tmp.gsql\""

    docker exec -it ${container_id} /bin/bash -c  "su - omm -c \"gsql -f ~/tmp.gsql >/dev/null\""
    echo_info "======Deploying openGauss Server Done!======"
}

#=======Gopher Deployment=======#
GOPHER_CONF='/opt/gala-gopher/gala-gopher.conf'
GOPHER_APP_CONF='/opt/gala-gopher/gala-gopher-app.conf'
PG_STAT_CONF='/opt/gala-gopher/extend_probes/pg_stat_probe.conf'
STACKPROBE_CONF='/opt/gala-gopher/extend_probes/stackprobe.conf'
function parse_arg_gopher() {
    ARGS=`getopt -a -o K:p:Ut: --long kafka:,pyroscope:,update,tag:,docker,proxy -- "$@"`
    [ $? -ne 0 ] && echo_err_exit "parse arg error, terminating..."
    eval set -- "${ARGS}"
    while true
    do
        case $1 in
            -K|--kafka)
                KAFKA_ADDR=$(addr_add_port $2 ${KAFKA_PORT})
                shift;;
            -p|--pyroscope)
                PYROSCOPE_ADDR=$(addr_add_port $2 ${PYROSCOPE_PORT})
                shift;;
            -U|--update)
                UPDATE_GALA="yes";;
            -t|--tag)
                DOCKER_TAG=$2
                shift;;
            --docker)
                GALA_DEPLOY_MODE="docker";;
            --proxy)
                DOCKER_USE_PROXY="yes";;
            --)
                shift
                break;;
            *)
                echo_err_exit "getopt param error";;
        esac
        shift
    done
}

function deploy_gopher_rpm() {
    echo -e "[1] Installing gala-gopher"
    install_rpm gala-gopher

    echo -e "\n[2] Configuring gala-gopher"
    if [ ! -f "${GOPHER_CONF}" ] ; then
        GOPHER_CONF='/etc/gala-gopher/gala-gopher.conf'
        GOPHER_APP_CONF='/etc/gala-gopher/gala-gopher-app.conf'
        PG_STAT_CONF='/etc/gala-gopher/extend_probes/pg_stat_probe.conf'
        STACKPROBE_CONF='/etc/gala-gopher/extend_probes/stackprobe.conf'
    fi
    # kafka broker
    sed -i "s#kafka_broker =.*#kafka_broker = \"${KAFKA_ADDR}\"#g" ${GOPHER_CONF}

    # pg_stat_probe.conf
    line=$(grep -n '  -' ${PG_STAT_CONF} | head -1 | cut -f1 -d':')
    sed -i "$((line+1)),\$d" ${PG_STAT_CONF}
    cat >> ${PG_STAT_CONF} << EOF
    ip: "172.11.0.101"
    port: "5432"
    dbname: "postgres"
    user: "opengauss_exporter"
    password: "opengauss_exporter123"
EOF

    # add guassdb to app whitelist
    if ! grep -q 'comm = "gaussdb"' ${GOPHER_APP_CONF} ; then
        sed -i "/^(/a\ \t{\n\t\tcomm = \"gaussdb\",\n\t\tcmdline = \"\";\n\t},"  ${GOPHER_APP_CONF}
    fi

    # stackprobe.conf
    sed -i "/name = \"stackprobe\"/{n;n;n;s/switch =.*/switch = \"on\"/g;}" ${GOPHER_CONF}
    sed -i "s/pyroscope_server.*/pyroscope_server = \"${PYROSCOPE_ADDR}\";/g" ${STACKPROBE_CONF}

    echo -e "\n[3] Starting gala-gopher service"
    systemctl restart gala-gopher || echo_err_exit "Error: fail to start gala-gopher.service"
}

function deploy_gopher_docker() {
    container_name="aops-gala-gopher"

    [ -z "${DOCKER_TAG}" ] && echo_err_exit "Error: must specify tag when deploying in docker mode"
    echo -e "[1] Pulling gala-gopher docker image for ${DOCKER_TAG}"
    gopher_tag="gala-gopher-$(uname -m):${DOCKER_TAG}"
    docker_pull_image "${gopher_tag}"

    echo -e "\n[2] Configuring gala-gopher"
    \cp -rf gopher_user_conf /opt
    # kafka broker
    sed -i "s#kafka_broker =.*#kafka_broker = \"${KAFKA_ADDR}\"#g" /opt/gopher_user_conf/gala-gopher.conf

    # pg_stat_probe.conf
    mkdir -p /opt/gopher_user_conf/extend_probes
    cat > /opt/gopher_user_conf/extend_probes/pg_stat_probe.conf << EOF
servers:
  -
    ip: "172.11.0.101"
    port: "5432"
    dbname: "postgres"
    user: "opengauss_exporter"
    password: "opengauss_exporter123"
EOF
    # add guassdb to app whitelist
    if ! grep -q 'comm = "gaussdb"' /opt/gopher_user_conf/gala-gopher-app.conf ; then
        sed -i "/^(/a\ \t{\n\t\tcomm = \"gaussdb\",\n\t\tcmdline = \"\";\n\t}," /opt/gopher_user_conf/gala-gopher-app.conf
    fi

    # stackprobe.conf
    sed -i "/name = \"stackprobe\"/{n;n;n;s/switch =.*/switch = \"on\"/g;}" /opt/gopher_user_conf/gala-gopher.conf
    sed -i "s/pyroscope_server.*/pyroscope_server = \"${PYROSCOPE_ADDR}\";/g" /opt/gopher_user_conf/extend_probes/stackprobe.conf

    echo -e "\n[3] Creating gala-gopher container"
    # Stop gala-gopher service to prevent port conflict
    systemctl stop gala-gopher 2>/dev/null
    docker stop ${container_name} 2>/dev/null ; docker rm ${container_name} 2>/dev/null
    docker run -d --name ${container_name} --privileged \
        -v /etc:/etc -v /var:/var  -v /boot:/boot:ro \
        -v /lib/modules:/lib/modules:ro -v /usr/src:/usr/src:ro \
        -v /opt/gopher_user_conf/:/gala-gopher/user_conf/ \
        -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf  \
        --pid=host --network=host  ${DOCKER_HUB_TAG_PREFIX}/"${gopher_tag}"
    [ $? -ne 0 ] && echo_err_exit "Error: fail to run gala-gopher container"
}

function deploy_gopher() {
    echo_info "======Deploying gala-gopher(${GALA_DEPLOY_MODE})======"
    if [ "x${GALA_DEPLOY_MODE}" == "xrpm" ]  ; then
        if [ "x${os_version}" == "xother" ] ; then
            echo_warn "Try installing local gopher rpm"
            install_local_rpm "${LIBBPF_LOCAL_RPM}"
            install_local_rpm "${FLAMEGRAPH_LOCAL_RPM}"
            install_local_rpm "${GOPHER_LOCAL_RPM}"
        fi
        deploy_gopher_rpm
    elif [ "x${GALA_DEPLOY_MODE}" == "xdocker" ] ; then
        deploy_gopher_docker
    else
        echo_err_exit "Unsupported deploy mode, must be rpm or docker"
    fi
    echo_info "======Deploying gala-gopher Done!======"
}


#=======Ops Deployment=======#
ANTEATER_CONF='/etc/gala-anteater/config/gala-anteater.yaml'
SPIDER_CONF='/etc/gala-spider/gala-spider.yaml'
INFERENCE_CONF='/etc/gala-inference/gala-inference.yaml'
ANTEATER_KAFKA_IP="localhost"
ANTEATER_PROMETHEUS_IP="localhost"
function parse_arg_ops() {
    ARGS=`getopt -a -o K:P:A:U --long kafka:,prometheus:,arangodb:,update,docker,proxy -- "$@"`
    [ $? -ne 0 ] && echo_err_exit "parse arg error, terminating..."
    eval set -- "${ARGS}"
    while true
    do
        case $1 in
            -K|--kafka)
                KAFKA_ADDR=$(addr_add_port $2 ${KAFKA_PORT})
                KAFKA_PORT=$(get_port_from_addr ${KAFKA_ADDR})
                ANTEATER_KAFKA_IP=$(get_ip_from_addr ${KAFKA_ADDR})
                shift;;
            -U|--update)
                UPDATE_GALA="yes";;
            -P|--prometheus)
                PROMETHEUS_ADDR=$(addr_add_port $2 ${PROMETHEUS_PORT})
                PROMETHEUS_PORT=$(get_port_from_addr ${PROMETHEUS_ADDR})
                ANTEATER_PROMETHEUS_IP=$(get_ip_from_addr ${PROMETHEUS_ADDR})
                shift;;
            -A|--arangodb)
                ARANGODB_ADDR=$(addr_add_port $2 ${ARANGODB_PORT})
                shift;;
            --docker)
                GALA_DEPLOY_MODE="docker";;
            --proxy)
                DOCKER_USE_PROXY="yes";;
            --)
                shift
                break;;
            *)
                echo_err_exit "getopt param error";;
        esac
        shift
    done
}

function deploy_ops_rpm() {
    echo -e "[1] Installing gala-ops"
    install_rpm gala-ops

    echo -e "\n[2] Configuring gala-ops"
    sed -i "/^Kafka:/{n;s/server:.*/server: \"${ANTEATER_KAFKA_IP}\"/g;}" ${ANTEATER_CONF}
    sed -i "/^Kafka:/{n;n;s/port:.*/port: \"${KAFKA_PORT}\"/g;}" ${ANTEATER_CONF}
    sed -i "/^Prometheus:/{n;s/server:.*/server: \"${ANTEATER_PROMETHEUS_IP}\"/g;}" ${ANTEATER_CONF}
    sed -i "/^Prometheus:/{n;n;s/port:.*/port: \"${PROMETHEUS_PORT}\"/g;}" ${ANTEATER_CONF}

    sed -i "/^prometheus:/{n;s/base_url:.*/base_url: \"http:\/\/${PROMETHEUS_ADDR}\/\"/g;}" ${SPIDER_CONF}
    sed -i "/^kafka:/{n;s/server:.*/server: \"${KAFKA_ADDR}\"/g;}" ${SPIDER_CONF}
    sed -i "/db_conf:/{n;s/url:.*/url: \"http:\/\/${ARANGODB_ADDR}\"/g;}" ${SPIDER_CONF}
    sed -i "s/  log_level:.*/  log_level: DEBUG/g" ${SPIDER_CONF}

    sed -i "/^prometheus:/{n;s/base_url:.*/base_url: \"http:\/\/${PROMETHEUS_ADDR}\/\"/g;}" ${INFERENCE_CONF}
    sed -i "/^kafka:/{n;s/server:.*/server: \"${KAFKA_ADDR}\"/g;}" ${INFERENCE_CONF}
    sed -i "/^arangodb:/{n;s/url:.*/url: \"http:\/\/${ARANGODB_ADDR}\"/g;}" ${INFERENCE_CONF}
    sed -i "s/  log_level:.*/  log_level: DEBUG/g" ${INFERENCE_CONF}

    echo -e "\n[3] Starting gala-ops service"
    systemctl restart gala-anteater || echo_err_exit "Error: fail to start gala-anteater service"
    systemctl restart gala-spider gala-inference || echo_err_exit "Error: fail to start gala-spider or gala-inference service"
}

function deploy_ops_docker() {
    echo -e "[1] Pulling gala-spider/gala-inference/gala-anteater docker image"

    spider_tag="gala-spider-$(uname -m):1.0.1"
    infer_tag="gala-inference-$(uname -m):1.0.1"
    anteater_tag="gala-anteater-$(uname -m):1.0.1"
    docker_pull_image "${spider_tag}"
    docker_pull_image "${infer_tag}"
    docker_pull_image "${anteater_tag}"

    echo -e "\n[2] Creating gala-spider/gala-inference/gala-anteater container"
    docker stop gala-spider-demo 2>/dev/null ; docker rm gala-spider-demo 2>/dev/null
    docker run -d --name gala-spider-demo \
        -e prometheus_server=${PROMETHEUS_ADDR} \
        -e arangodb_server=${ARANGODB_ADDR}  \
        -e kafka_server=${KAFKA_ADDR} \
        -e log_level=DEBUG --network host ${DOCKER_HUB_TAG_PREFIX}/"${spider_tag}"
    [ $? -ne 0 ] && echo_err_exit "Error: fail to run gala-spider container"

    docker stop gala-inference-demo 2>/dev/null ; docker rm gala-inference-demo 2>/dev/null
    docker run -d --name gala-inference-demo \
        -e prometheus_server=${PROMETHEUS_ADDR} \
        -e arangodb_server=${ARANGODB_ADDR} \
        -e kafka_server=${KAFKA_ADDR} \
        -e log_level=DEBUG --network host ${DOCKER_HUB_TAG_PREFIX}/"${infer_tag}"
    [ $? -ne 0 ] && echo_err_exit "Error: fail to run gala-inference container"

    mkdir -p /etc/gala-anteater/config/
    \cp -f ./gala-anteater/gala-anteater.yaml /etc/gala-anteater/config/
    sed -i "/^Kafka:/{n;s/server:.*/server: \"${ANTEATER_KAFKA_IP}\"/g;}" ${ANTEATER_CONF}
    sed -i "/^Kafka:/{n;n;s/port:.*/port: \"${KAFKA_PORT}\"/g;}" ${ANTEATER_CONF}
    sed -i "/^Prometheus:/{n;s/server:.*/server: \"${ANTEATER_PROMETHEUS_IP}\"/g;}" ${ANTEATER_CONF}
    sed -i "/^Prometheus:/{n;n;s/port:.*/port: \"${PROMETHEUS_PORT}\"/g;}" ${ANTEATER_CONF}

    docker stop gala-anteater-demo 2>/dev/null ; docker rm gala-anteater-demo 2>/dev/null
    docker run -d --name gala-anteater-demo \
        -v /etc/gala-anteater/config/gala-anteater.yaml:/etc/gala-anteater/config/gala-anteater.yaml \
        --network host ${DOCKER_HUB_TAG_PREFIX}/"${anteater_tag}"
    [ $? -ne 0 ] && echo_err_exit "Error: fail to run gala-anteater container"
}


function deploy_ops() {
    echo_info "======Deploying gala-ops(${GALA_DEPLOY_MODE})======"
    if [ "x${GALA_DEPLOY_MODE}" == "xrpm" ]  ; then
        if [ "x${os_version}" == "xother" ] ; then
            echo_err_exit "Error: anteater only support 22.03 LTS/22.03 LTS SP1 in rpm mode, try run with --docker"
        fi
        deploy_ops_rpm
    elif [ "x${GALA_DEPLOY_MODE}" == "xdocker" ] ; then
        deploy_ops_docker
    else
        echo_err_exit "Unsupported deploy mode, must be rpm or docker"
    fi
    echo_info "======Deploying gala-ops Done!======"
}

#=======Middleware Deployment=======#
middleware_deploy_list=""
function parse_arg_middleware() {
    ARGS=`getopt -a -o K:P:E:A --long kafka:,prometheus:,elastic:,arangodb,proxy -- "$@"`
    [ $? -ne 0 ] && echo_err_exit "parse arg error, terminating..."
    eval set -- "${ARGS}"
    while true
    do
        case $1 in
            -K|--kafka)
                KAFKA_ADDR=$(addr_add_port $2 ${KAFKA_PORT})
                middleware_deploy_list="${middleware_deploy_list}kafka "
                shift;;
            -P|--prometheus)
                PROMETHEUS_SCRAPE_LIST="$2"
                middleware_deploy_list="${middleware_deploy_list}prometheus "
                shift;;
            -E|--elastic)
                ES_ADDR=$(addr_add_port "$2" ${ES_PORT})
                middleware_deploy_list="${middleware_deploy_list}elasticsearch "
                shift;;
            -A|--arangodb)
                middleware_deploy_list="${middleware_deploy_list}arangodb "
                ;;
            --proxy)
                DOCKER_USE_PROXY="yes";;
            --)
                shift
                break;;
            *)
                echo_err_exit "getopt param error";;
        esac
        shift
    done
}

KAFKA_WORKDIR='/opt/kafka/'
function deploy_kafka() {
    echo -e "[-] Deploy kafka"
    echo -e "Installing..."
    install_rpm kafka

    echo -e "Configuring..."
    sed -i "0,/.*listeners=.*/s//listeners=PLAINTEXT:\/\/${KAFKA_ADDR}/" ${KAFKA_WORKDIR}/config/server.properties

    echo -e "Starting..."
    cd ${KAFKA_WORKDIR}
        ./bin/kafka-server-stop.sh
        ./bin/zookeeper-server-stop.sh
        ./bin/zookeeper-server-start.sh config/zookeeper.properties >/dev/null 2>&1 &
        sleep 20
        ./bin/kafka-server-start.sh config/server.properties >/dev/null 2>&1 &
    cd - >/dev/null
}

PROMETHEUS_CONF='/etc/prometheus/prometheus.yml'
function deploy_prometheus2() {
    echo -e "[-] Deploy prometheus2"
    echo -e "Installing..."
    install_rpm prometheus2

    echo -e "Configuring..."
    \cp -f ${PROMETHEUS_CONF} "${PROMETHEUS_CONF}.bak"
    line=$(grep -n scrape_configs ${PROMETHEUS_CONF} | cut -f1 -d':')
    sed -i "$((line+1)),\$d" ${PROMETHEUS_CONF}
    scrape_array=(${PROMETHEUS_SCRAPE_LIST//,/ })

    for var in ${scrape_array[@]}
    do
        port=""
        job_name=${var%:*}
        if echo $var | grep -q ":" ; then
            port=${var##*:}
        fi
        port=${port:-8888}
        scrape_addr=${job_name##*-}

        cat >> ${PROMETHEUS_CONF} << EOF
  - job_name: "${job_name}"
    static_configs:
      - targets: ["${scrape_addr}:${port}"]

EOF
    done

    echo -e "Starting..."
    systemctl restart prometheus.service || echo_err_exit "Error: fail to start prometheus.service"
}

function deploy_arangodb_docker() {
    container_name="aops-arangodb"
    if docker inspect ${container_name} >/dev/null 2>&1 ; then
        echo -e "arangodb container has already been created, running"
        docker start ${container_name} || echo_err_exit "Error: fail to run arangodb container"
        return
    fi

    echo -e "Pulling arangodb docker images"
    arangodb_tag="arangodb-$(uname -m)"
    docker_pull_image "${arangodb_tag}"

    echo -e "Creating and running arangodb container"
    docker run -d --name ${container_name} -p 8529:8529 -e ARANGO_NO_AUTH=yes ${DOCKER_HUB_TAG_PREFIX}/${arangodb_tag}
    [ $? -ne 0 ] && echo_err_exit "Error: fail to run arangodb container"
}

ARANGODB_CONF='/etc/arangodb3/arangod.conf'
function deploy_arangodb() {
    echo -e "[-] Deploy arangodb"
    if [ $(uname -m) != 'x86_64' ] ; then
        echo_warn "Arangodb only available on x86_64 in rpm mode, try docker mode..."
        deploy_arangodb_docker
        return
    fi

    if [ "x${os_version}" == "xother" ] ; then
        echo_warn "Arangodb only support 22.03 LTS/22.03 LTS SP1 in rpm mode, try docker mode..."
        deploy_arangodb_docker
        return
    fi

    echo -e "Installing..."
    install_rpm arangodb3

    echo -e "Configuring..."
    sed -i 's/authentication =.*/authentication = false/g' ${ARANGODB_CONF}

    echo -e "Starting..."
    systemctl restart arangodb3.service || echo_err_exit "Error: fail to start arangodb3 service"
}

function deploy_elasticsearch() {
    echo_info "======Deploying Elasticsearch======"
    echo -e "[1] Downloading es tarball"
    if [ ! -f ./elasticsearch-8.5.3-linux-$(uname -m).tar.gz ] ; then
        wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.5.3-linux-$(uname -m).tar.gz --no-check-certificate
        [ $? -ne 0 ] && echo_err_exit "Error: fail to download elasticsearch rpm from official website, check proxy!"
    fi

    echo -e "\n[2] Creating elasticsearch-used user/group"
    groupadd elastic
    useradd -g elastic elastic
    \cp -f ./elasticsearch-8.5.3-linux-$(uname -m).tar.gz /home/elastic
    chown elastic:elastic /home/elastic/elasticsearch-8.5.3-linux-$(uname -m).tar.gz

    echo -e "\n[3] Starting es process"
    kill -9 $(ps -ef | grep elasticsearch-8.5.3 | awk '{if($3==1) print $2}')  2>/dev/null
    su - elastic -c "tar xzfm elasticsearch-8.5.3-linux-$(uname -m).tar.gz && \
        cd elasticsearch-8.5.3 && \
        ES_JAVA_OPTS=\"-Xms1g -Xmx1g\" ./bin/elasticsearch -E xpack.security.enabled=false -E http.host=0.0.0.0 -d"
    echo_info "======Deploying Elasticsearch Done======"
    deploy_logstash
}

function deploy_logstash() {
    echo_info "======Deploying Logstash======"
    echo -e "[1] Downloading logstash rpm and install"
    if rpm -qa | grep -q logstash ; then
       echo "logstash is already installed, skip..."
    elif [ ! -f ./logstash-8.5.3-$(uname -m).rpm ] ; then
        wget https://artifacts.elastic.co/downloads/logstash/logstash-8.5.3-$(uname -m).rpm --no-check-certificate
        [ $? -ne 0 ] && echo_err_exit "Error: fail to download logstash rpm from official website, check proxy!"
        yum install logstash-8.5.3-$(uname -m).rpm -y
    else
        yum install logstash-8.5.3-$(uname -m).rpm -y
    fi

    echo -e "\n[2] Configure logstash"
    rm -f /etc/logstash/logstash-sample.conf
    cat > /etc/logstash/conf.d/kafka2es.conf << EOF
input {
  kafka {
    bootstrap_servers => "${KAFKA_ADDR}"
    topics => ["gala_anteater_hybrid_model", "gala_cause_inference"]
    group_id => "hh_group"
    client_id => "hh_client"
    decorate_events => "true"
  }
}

filter {
  json {
    source => "message"
  }

  date {
    match => ["Timestamp", "UNIX_MS"]
    target => "@timestamp"
  }
}

output {
  elasticsearch {
    hosts => "${ES_ADDR}"
    index => "%{[@metadata][kafka][topic]}-%{+YYYY.MM.dd}"
  }
}
EOF

    echo -e "\n[3] Starting logstash service"
    cd /usr/share/logstash
    kill -9 $(ps -ef | grep logstash | grep 'kafka2es.conf' | awk '{print $2}') 2>/dev/null
    (nohup ./bin/logstash -f  /etc/logstash/conf.d/kafka2es.conf &) || echo_err_exit "Error: fail to start logstash service"
    cd - > /dev/null
    echo_info "======Deploying Logstash Done======"
}

function deploy_middleware() {
    echo_info "======Deploying MiddleWare======"
    [[ "${middleware_deploy_list}" =~ "kafka" ]] && deploy_kafka
    [[ "${middleware_deploy_list}" =~ "prometheus" ]] && deploy_prometheus2
    [[ "${middleware_deploy_list}" =~ "arangodb" ]] && deploy_arangodb
    [[ "${middleware_deploy_list}" =~ "elasticsearch" ]] && deploy_elasticsearch

    echo_info "======Deploying MiddleWare Done!======"
}


#=======Grafana Deployment=======#
function parse_arg_grafana() {
    ARGS=`getopt -a -o P:p:E:A: --long prometheus:,pyroscope:,elastic:,arangodb:,proxy -- "$@"`
    [ $? -ne 0 ] && echo_err_exit "parse arg error, terminating..."
    eval set -- "${ARGS}"
    while true
    do
        case $1 in
            -P|--prometheus)
                PROMETHEUS_ADDR=$(addr_add_port "$2" ${PROMETHEUS_PORT})
                shift;;
            -p|--pyroscope)
                PYROSCOPE_ADDR=$(addr_add_port "$2" ${PYROSCOPE_PORT})
                shift;;
            -E|--elastic)
                ES_ADDR=$(addr_add_port "$2" ${ES_PORT})
                shift;;
            --proxy)
                DOCKER_USE_PROXY="yes";;
            -A|--arangodb)
                ARANGODB_ADDR=$(addr_add_port "$2" ${ARANGODB_PORT})
                shift;;
            --)
                shift
                break;;
            *)
                echo_err_exit "getopt param error";;
        esac
        shift
    done
}

function deploy_pyroscope() {
    if ps -ef | grep -v grep | grep -q 'pyroscope server' ; then
        echo_info "pyroscope is already running, skip..."
        return
    fi

    if rpm -qa | grep -q pyroscope ; then
        \cp -f /usr/lib/pyroscope/scripts/pyroscope-server.service /usr/lib/systemd/system/
        systemctl start pyroscope-server
        return
    elif [ ! -f ./pyroscope-0.36.0-1-$(uname -m).rpm ] ; then
        wget https://dl.pyroscope.io/release/pyroscope-0.36.0-1-$(uname -m).rpm --no-check-certificate
        [ $? -ne 0 ] && echo_err_exit "Error: fail to download pyroscope rpm from official website, check proxy!"
        yum install pyroscope-0.36.0-1-$(uname -m).rpm -y

    else
        yum install pyroscope-0.36.0-1-$(uname -m).rpm -y
    fi

    \cp -f /usr/lib/pyroscope/scripts/pyroscope-server.service /usr/lib/systemd/system/
    systemctl start pyroscope-server || echo_err_exit "Error: fail to start pyroscope service"
}

function get_grafana_datasourcesID_byName() {
    d_name="$1"

    d_id=$(curl -X GET -H "Content-Type: application/json" http://admin:admin@localhost:3000/api/datasources/id/${d_name} 2>/dev/null)
    if echo $d_id | grep -q 'not found' ; then
        echo_err_exit "Failed to find datasource ${d_name} in grafana"
    fi

    d_id=${d_id##*:}
    d_id=${d_id%?}
    echo $d_id
}


function deploy_grafana() {
    container_name="aops-grafana"

    echo_info "======Deploying Grafana======"
    echo -e "[1] Deploying pyroscope"
    deploy_pyroscope

    if docker inspect ${container_name} >/dev/null 2>&1 ; then
        docker stop ${container_name}
        docker rm ${container_name}
    fi

    echo -e "\n[2] Pulling grafana docker image"
    docker_pull_image "grafana"

    echo -e "\n[3] Importing grafana dashboard and plugins"
    mkdir -p /opt/grafana
    \cp -rf grafana/* /opt/grafana

    echo -e "\n[4] Creating grafana container"
    docker stop ${container_name} 2>/dev/null ; docker rm ${container_name} 2>/dev/null
    docker run -d --name ${container_name} --network host -v /opt/grafana:/var/lib/grafana/ ${DOCKER_HUB_TAG_PREFIX}/grafana
    [ $? -ne 0 ] && echo_err_exit "Error: fail to run grafana container"

    echo -e "\n[5] Configuring datasources"
    i=0
    while ! netstat -tunpl | grep ':3000' | grep 'LISTEN' | grep -q 'grafana' ; do
        sleep 1
        let i+=1
        if [ $i -ge 10 ] ; then
            echo_err_exit "Fail to connect grafana, check container status"
        fi
    done

    name="Prometheus-dfs"
    id=$(get_grafana_datasourcesID_byName ${name})
    result=$(curl -X PUT -H "Content-Type: application/json" -d '{"id":'${id}',"name":"'${name}'","type":"prometheus",
"access":"proxy","url":"http://'${PROMETHEUS_ADDR}'","user":"","database":"",
"basicAuth":false,"isDefault":true,"jsonData":{"httpMethod":"POST"},"readOnly":false}' \
http://admin:admin@localhost:3000/api/datasources/${id} 2>/dev/null)
    if ! echo $result | grep -q 'Datasource updated' ; then
        echo_err_exit "Fail to update ${name} datesource in grafana"
    fi

    name="pyroscope-datasource"
    id=$(get_grafana_datasourcesID_byName ${name})
    result=$(curl -X PUT -H "Content-Type: application/json" -d '{"id":'${id}',"name":"'${name}'","type":"pyroscope-datasource",
"access":"proxy","url":"","user":"","database":"","basicAuth":false,"isDefault":false,
"jsonData":{"path":"http://'${PYROSCOPE_ADDR}'"},"readOnly":false}' \
http://admin:admin@localhost:3000/api/datasources/${id} 2>/dev/null)
    if ! echo $result | grep -q 'Datasource updated' ; then
        echo_err_exit "Fail to update ${name} datesource in grafana"
    fi

    name="Elasticsearch-anteater_hybrid_model"
    id=$(get_grafana_datasourcesID_byName ${name})
    result=$(curl -X PUT -H "Content-Type: application/json" -d '{"id":'${id}',"name":"'${name}'","type":"elasticsearch",
"access":"proxy","url":"http://'${ES_ADDR}'","user":"",
"database":"[gala_anteater_hybrid_model-]YYYY.MM.DD","basicAuth":false,"isDefault":false,
"jsonData":{"includeFrozen":false,"interval":"Daily","logLevelField":"","logMessageField":"","maxConcurrentShardRequests":5,"timeField":"@timestamp"},
"readOnly":false}' http://admin:admin@localhost:3000/api/datasources/${id} 2>/dev/null)
    if ! echo $result | grep -q 'Datasource updated' ; then
        echo_err_exit "Fail to update ${name} datesource in grafana"
    fi

    name="Elasticsearch-cause_inference"
    id=$(get_grafana_datasourcesID_byName ${name})
    result=$(curl -X PUT -H "Content-Type: application/json" -d '{"id":'${id}',"name":"'${name}'","type":"elasticsearch",
"access":"proxy","url":"http://'${ES_ADDR}'","user":"",
"database":"[gala_cause_inference-]YYYY.MM.DD","basicAuth":false,"isDefault":false,
"jsonData":{"includeFrozen":false,"interval":"Daily","logLevelField":"","logMessageField":"","maxConcurrentShardRequests":5,"timeField":"@timestamp"},
"readOnly":false}' http://admin:admin@localhost:3000/api/datasources/${id} 2>/dev/null)
    if ! echo $result | grep -q 'Datasource updated' ; then
        echo_err_exit "Fail to update ${name} datesource in grafana"
    fi

    name="Elasticsearch-cause_inference_top"
    id=$(get_grafana_datasourcesID_byName ${name})
    result=$(curl -X PUT -H "Content-Type: application/json" -d '{"id":'${id}',"name":"'${name}'","type":"elasticsearch",
"access":"proxy","url":"http://'${ES_ADDR}'","user":"",
"database":"[gala_cause_inference-]YYYY.MM.DD","basicAuth":false,"isDefault":false,
"jsonData":{"includeFrozen":false,"interval":"Daily","logLevelField":"","logMessageField":"_source.Resource.top1","maxConcurrentShardRequests":5,"timeField":"@timestamp"},
"readOnly":false}' http://admin:admin@localhost:3000/api/datasources/${id} 2>/dev/null)
    if ! echo $result | grep -q 'Datasource updated' ; then
        echo_err_exit "Fail to update ${name} datesource in grafana"
    fi

    name="Elasticsearch-graph"
    id=$(get_grafana_datasourcesID_byName ${name})
    result=$(curl -X PUT -H "Content-Type: application/json" -d '{"id":'${id}',"name":"'${name}'","type":"elasticsearch",
"access":"proxy","url":"http://'${ES_ADDR}'","user":"",
"database":"aops_graph2","basicAuth":false,"isDefault":false,
"jsonData":{"includeFrozen":false,"logLevelField":"","logMessageField":"_source","maxConcurrentShardRequests":5,"timeField":"timestamp"},
"readOnly":false}' http://admin:admin@localhost:3000/api/datasources/${id} 2>/dev/null)
    if ! echo $result | grep -q 'Datasource updated' ; then
        echo_err_exit "Fail to update ${name} datesource in grafana"
    fi

    # Create topo graph es resources
    curl -X PUT "${ES_ADDR}/aops_graph2?pretty" >/dev/null 2>&1

    # Running daemon that transfrom arangodb to es
    pip install -q elasticsearch python-arango pytz pyArango -i http://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
    [ $? -ne 0 ] && echo_err_exit "Fail to pip install dependencies for arangodb2es.py"
    sed -i "s/self.arangodbUrl =.*/self.arangodbUrl = 'http:\/\/${ARANGODB_ADDR}'/g" /opt/grafana/arangodb2es.py
    sed -i "s/self.esUrl =.*/self.esUrl = 'http:\/\/${ES_ADDR}'/g" /opt/grafana/arangodb2es.py
    sed -i "s/self.promethusUrl =.*/self.promethusUrl = 'http:\/\/${PROMETHEUS_ADDR}'/g" /opt/grafana/arangodb2es.py

    kill -9 $(ps -ef | grep arangodb2es.py | grep -v grep | awk '{print $2}')  2>/dev/null
    python3 /opt/grafana/arangodb2es.py >/dev/null 2>&1 &

    echo_info "======Deploying Grafana Done======"
}

#=======Main=======#
check_osversion_decide_repo
COMPONENT="$1"
shift

case "x$COMPONENT" in
    xgopher)
        parse_arg_gopher $@
        deploy_gopher
        ;;
    xops)
        parse_arg_ops $@
        deploy_ops
        ;;
    xopengauss)
        parse_arg_opengauss_server $@
        deploy_opengauss_server
        ;;
    xmiddleware)
        parse_arg_middleware $@
        deploy_middleware
        ;;
    xgrafana)
        parse_arg_grafana $@
        deploy_grafana
        ;;
    x)
        echo "Must specify a componet to be deployed!"
        print_usage
        exit 1
        ;;
    *)
        echo "Unsupport component:" $COMPONENT
        print_usage
        exit 1
        ;;
esac
